package com.young.fs.web;

import com.young.fs.exception.FsException;
import com.young.common.util.CommonUtil;
import com.young.common.util.FileDownloadUtil;
import com.young.common.util.Result;
import com.young.common.util.StringUtils;
import com.young.fs.model.EFileType;
import com.young.fs.model.FileInfo;
import com.young.fs.service.IFileInfoService;
import com.young.fs.service.IFileService;
import com.young.fs.util.FsConstants;
import com.young.interfaces.log.annotation.Log;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件处理Controller
 * yangwei
 */
@Controller
@RequestMapping(value = "/fs/file", method = {RequestMethod.GET, RequestMethod.POST})
public class FsFileController {

    @Resource(name="fsFileService")
    IFileService fileService;

    @Resource(name="fsFileInfoService")
    IFileInfoService fileInfoService;

    private static final Logger logger = LoggerFactory.getLogger(FsFileController.class);


    /**
     * 文件上传统一入口
     * @param file
     * @param request
     * @return
     */
    @Log("上传文件")
    @RequestMapping("/upload")
    @ResponseBody
    public Object upload(MultipartFile file, String folderId, String businessCode, HttpServletRequest request) {
        logger.info("[文件上传] 文件夹编号为：{},业务编号为: {}", folderId, businessCode);
        if (file != null && !file.isEmpty()){
            FileInfo fileInfo = null;
            if (StringUtils.isNotBlank(folderId)){
                fileInfo = fileService.saveFile(file, folderId, businessCode);//保存文件
            }else{
                fileInfo = fileService.saveFile(file, businessCode);//保存文件
            }
            List<FileInfo> list = new ArrayList<FileInfo>();
            list.add(fileInfo);
            return Result.buildSuccess(list);
        }else{
            return Result.buildFail("文件不存在!");
        }
    }

    /**
     * 文件下载
     * @param fileId
     * @param request
     * @throws Exception
     */
    @Log("下载文件")
    @RequestMapping("/download")
    public void download(String fileId, HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("[文件下载] 待下载文件编号为:{}", fileId);
        FileInfo fileInfo = fileInfoService.getFileInfo(fileId);
        if (fileInfo != null) {
            File file = new File(fileInfo.getAddr());
            if (!file.exists()) {
                logger.warn("[下载文件] 文件[id={}]不存在:对应文件不存在,存储地址={}", fileId, fileInfo.getAddr());
                CommonUtil.write2Response(response, "文件信息无效!");
                return;
            }
            String fileName = fileInfo.getName();
            response.setContentType("application/x-msdownload;");//文件下载类型
            FileDownloadUtil.setFileNameOfCN(request, response, fileName);//设置中文文件名
            response.setHeader("Content-Length", String.valueOf(file.length()));//设置内容长度
            OutputStream os = response.getOutputStream();
            IOUtils.copy(new FileInputStream(file), os);//拷贝到输出流
        } else {
            logger.warn("[下载文件] 文件[id={}]不存在:找不到对应的文件存根!", fileId);
            CommonUtil.write2Response(response, "文件信息无效!");
        }

    }

    /**
     * 预览文件
     * @param id 文件编号
     * @param request
     * @param response
     * @throws Exception
     */
    @Log("预览文件")
    @RequestMapping("/preview/{id}")
    public void preview(@PathVariable("id")String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("[文件下载] 待预览文件编号为:{}", id);
        FileInfo fileInfo = fileInfoService.getFileInfo(id);
        if (fileInfo != null) {
            String fileName = fileInfo.getName();
            //设置响应类型
            if (EFileType.IMG.equals(fileInfo.getType())){
                response.setContentType("image/*");
            } else if (EFileType.VIDEO.equals(fileInfo.getType())){
                response.setContentType("video/*");
            } else if (EFileType.VOICE.equals(fileInfo.getType())){
                response.setContentType("video/*");
            } else if (EFileType.TXT.equals(fileInfo.getType())){
                response.setContentType("text/plain");
            } else if (EFileType.PDF.equals(fileInfo.getType())){
                response.setContentType("application/pdf");
            } else if (EFileType.DOC.equals(fileInfo.getType())){
                response.setContentType("application/msword");
            } else if (EFileType.EXCEL.equals(fileInfo.getType())){
                response.setContentType("application/vnd.ms-excel");
            } else if (EFileType.PPT.equals(fileInfo.getType())){
                response.setContentType("application/vnd.ms-powerpoint");
            } else {//默认为空
                //response.setContentType("application/x-msdownload;");
            }
            String userAgent = request.getHeader("User-Agent");//浏览器信息
            //Content-disposition设置为inline,在线打开
            //存在MSIE关键字,则是IE系列浏览器(IE11以后,取消掉了msie关键字),没有Chrome/Safari/Firefox/AppleWebKit/Opera等关键字,默认按照IE处理
            if(userAgent != null && ( userAgent.contains("MSIE") || (!userAgent.contains("Chrome") && !userAgent.contains("Safari")
                    && !userAgent.contains("Firefox") && !userAgent.contains("AppleWebKit") && !userAgent.contains("Opera")) ) ){
                //IE系浏览器下载时要对中文做编码处理(测试谷歌也可以这样,火狐会直接显示编码)
                response.setHeader("Content-disposition", "inline; filename=" + new String(URLEncoder.encode(fileName, "UTF-8")));
            }else{//非ie的下载处理
                response.setHeader("Content-disposition", "inline; filename=" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));
            }
            File file = new File(fileInfo.getAddr());
            if (!file.exists()) {
                logger.warn("[预览文件] 文件[id={}]不存在:对应文件不存在,存储地址={}", id, fileInfo.getAddr());
                CommonUtil.write2Response(response, "文件信息无效!");
                return;
            }
            response.setHeader("Content-Length", String.valueOf(file.length()));//设置内容长度
            OutputStream os = response.getOutputStream();
            IOUtils.copy(new FileInputStream(file), os);//拷贝到输出流
        } else {
            logger.warn("[预览文件] 文件[id={}]不存在:找不到对应的文件存根!", id);
            CommonUtil.write2Response(response, "文件信息无效!");
        }

    }

    /**
     * 删除文件
     * @param fileId 文件编号
     * @param request
     * @return
     */
    @Log("删除文件")
    @RequestMapping("/dropFile")
    @ResponseBody
    public Object dropFile(String fileId, HttpServletRequest request) {
        logger.info("[文件删除] 待删除文件编号为:{}", fileId);
        if (!fileService.dropFile(fileId)){
            return Result.buildFail("文件删除失败!");
        }
        return Result.buildSuccess();
    }

    /**
     * 删除文件夹
     * @param folderId
     * @param request
     * @return
     */
    @Log("删除文件夹")
    @RequestMapping("/dropFolder")
    @ResponseBody
    public Object dropFolder(String folderId, HttpServletRequest request) {
        logger.info("[文件夹删除] 待删除文件夹编号为:{}", folderId);
        if (!fileService.dropFolder(folderId)){
            return Result.buildFail("文件夹删除失败!");
        }
        return Result.buildSuccess();
    }

    /**
     * 创建文件夹
     * @param folder
     * @param request
     * @return
     */
    @Log("创建文件夹")
    @RequestMapping("/createFolder")
    @ResponseBody
    public Object createFolder(FileInfo folder, HttpServletRequest request) {
        if (folder == null || folder.getName() == null || folder.getFolderId() == null){
            return Result.buildFail("新建文件夹失败:所属文件夹或文件夹名称为空!");
        }else{
            List<FileInfo> list = new ArrayList<FileInfo>();
            list.add(fileService.createFolder(folder));
            return Result.buildSuccess(list);
        }
    }

    /**
     * 获取图片流
     * @param id
     * @param request
     * @param response
     * @throws Exception
     */
    @Log("获取图片流")
    @RequestMapping("/image")
    public void getImage(String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (StringUtils.isNotBlank(id)){
            FileInfo image = fileInfoService.getFileInfo(id);
            if (image != null){
                //图片文件
                File file = new File(image.getAddr());
                if (file.exists()){
                    InputStream is = new FileInputStream(file);//图片流
                    response.setContentType("image/*");//设置响应类型
                    //写入到响应
                    OutputStream os = response.getOutputStream();
                    IOUtils.copy(is, os);//拷贝到输出流
                }
            }
        }
    }

    /**
     * 获取图片流(restful形式)
     * @param id
     * @param request
     * @param response
     * @throws Exception
     */
    @Log("获取图片流")
    @RequestMapping("/image/{id}")
    public void getImage2(@PathVariable("id")String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (StringUtils.isNotBlank(id)){
            FileInfo image = fileInfoService.getFileInfo(id);
            if (image != null){
                //图片文件
                File file = new File(image.getAddr());
                if (file.exists()){
                    InputStream is = new FileInputStream(file);//图片流
                    response.setContentType("image/*");//设置响应类型
                    //写入到响应
                    OutputStream os = response.getOutputStream();
                    IOUtils.copy(is, os);//拷贝到输出流
                }
            }
        }
    }

    /**
     * 文件传输(接收端)
     * @param folderId 指定存储文件夹编号,默认为根目录
     * @param request
     * @return
     */
    @Log("接收传输文件")
    @RequestMapping("/transferFile")
    @ResponseBody
    public Object transferFile(String folderId, String businessCode, DefaultMultipartHttpServletRequest request) {
        List<MultipartFile> list = CommonUtil.getMultipartFileFromRequest(request);
        //若没有指定存储文件夹,使用根目录
        folderId = StringUtils.isNotBlank(folderId) ? folderId : FsConstants.ROOT_FOLDER_ID;
        if (list != null && list.size() > 0){
            //批量保存文件
            try {
                List<FileInfo> fsList = fileService.saveFiles(list, folderId, businessCode);
                return Result.buildSuccess(fsList);
            }catch (FsException e){//对于业务异常,做相关处理,给调用端提供详细错误信息
                logger.error("[文件传输] 文件保存异常", e);
                return Result.buildFail(e.getInfo());
            }
        }else{
            return Result.buildFail("文件不存在!");
        }
    }

}
